﻿using System;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Linq.Expressions;
using Moq.Language;

namespace Moq
{
    /// <summary>
    /// Represents XMock Extensions.
    /// </summary>
    public static class XMockExtensions
    {
        internal static Mock<TMock> Mock<TMock>(this TMock mockObject) where TMock : class
        {
            var type = mockObject.GetType();
            var mockProperty = type.GetProperty("Mock", typeof (Mock<TMock>));
            if (mockProperty == null)
            {
                throw new XMockException(
                    string.Format(CultureInfo.InvariantCulture, "The mock object('{0}') is not Mock type.", typeof (TMock).Name));
            }
            return (Mock<TMock>) mockProperty.GetValue(mockObject, null);
        }

        /// <summary>
        /// Gets the call base.
        /// </summary>
        /// <typeparam name="TMock">The type of the mock.</typeparam>
        /// <param name="mockObject">The mock object.</param>
        /// <returns></returns>
        public static bool CallBase<TMock>(this TMock mockObject) where TMock : class
        {
            return mockObject.Mock().CallBase;
        }

        /// <summary>
        /// Sets the call base.
        /// </summary>
        /// <typeparam name="TMock">The type of the mock.</typeparam>
        /// <param name="mockObject">The mock object.</param>
        /// <param name="callBase">if set to <c>true</c> [base members are executed].</param>
        /// <returns></returns>
        public static TMock WithCallBase<TMock>(this TMock mockObject, bool callBase) where TMock : class
        {
            mockObject.Mock().CallBase = callBase;
            return mockObject;
        }

        /// <summary>
        /// Gets the <see cref="DefaultValue"/> for mock object.
        /// </summary>
        /// <typeparam name="TMock">The type of the mock.</typeparam>
        /// <param name="mockObject">The mock object.</param>
        /// <returns></returns>
        public static DefaultValue DefaultValue<TMock>(this TMock mockObject) where TMock : class
        {
            return mockObject.Mock().DefaultValue;
        }

        /// <summary>
        /// Sets the <see cref="DefaultValue"/> for mock object.
        /// </summary>
        /// <typeparam name="TMock">The type of the mock.</typeparam>
        /// <param name="mockObject">The mock object.</param>
        /// <param name="defaultValue"><see cref="DefaultValue"/>.</param>
        /// <returns></returns>
        public static TMock WithDefaultValue<TMock>(this TMock mockObject, DefaultValue defaultValue) where TMock : class
        {
            mockObject.Mock().DefaultValue = defaultValue;
            return mockObject;
        }

        /// <summary>
        /// Gets the <see cref="MockBehavior"/>.
        /// </summary>
        /// <typeparam name="TMock">The type of the mock.</typeparam>
        /// <param name="mockObject">The mock object.</param>
        /// <returns></returns>
        public static MockBehavior MockBehavior<TMock>(this TMock mockObject) where TMock : class
        {
            return mockObject.Mock().Behavior;
        }

        /* Setup */

        /// <summary>
        /// Sets up a method of the specified mock object with return value.
        /// </summary>
        /// <typeparam name="TMock">The type of the mock.</typeparam>
        /// <typeparam name="TReturn">The type of the return.</typeparam>
        /// <param name="mockObject">The mock object.</param>
        /// <param name="expression">The expression to set up a method.</param>
        /// <param name="value">The return value.</param>
        /// <returns></returns>
        [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures")]
        public static TMock Setup<TMock, TReturn>(this TMock mockObject,
                                                  Expression<Func<TMock, TReturn>> expression,
                                                  TReturn value) where TMock : class
        {
            return Setup(mockObject, expression, value, args => { });
        }

        /// <summary>
        /// Sets up a method of the specified mock object with return value and call back method.
        /// </summary>
        /// <typeparam name="TMock">The type of the mock.</typeparam>
        /// <typeparam name="TReturn">The type of the return.</typeparam>
        /// <param name="mockObject">The mock object.</param>
        /// <param name="expression">The expression to set up a method.</param>
        /// <param name="value">The return value.</param>
        /// <param name="callback">The callback.</param>
        /// <returns></returns>
        [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures")]
        public static TMock Setup<TMock, TReturn>(this TMock mockObject,
                                                  Expression<Func<TMock, TReturn>> expression,
                                                  TReturn value,
                                                  Action<object[]> callback) where TMock : class
        {
            if (expression == null)
            {
                throw new ArgumentNullException("expression");
            }
            if (callback == null)
            {
                throw new ArgumentNullException("callback");
            }
            MethodCallExpression methodCallExpression;
            if ((methodCallExpression = expression.Body as MethodCallExpression) == null)
            {
                throw new ArgumentException("Expression should be for Method(not Property).");
            }
            int count = methodCallExpression.Arguments.Count;
            ICallback iCallback = mockObject.Mock().Setup(expression).Returns(value);
            iCallback.SetupCallBack(count, callback);
            return mockObject;
        }

        /// <summary>
        /// Sets up a method of the specified mock object with return function.
        /// </summary>
        /// <typeparam name="TMock">The type of the mock.</typeparam>
        /// <typeparam name="TReturn">The type of the return.</typeparam>
        /// <param name="mockObject">The mock object.</param>
        /// <param name="expression">The expression to set up a method.</param>
        /// <param name="valueFunction">The return function.</param>
        /// <returns></returns>
        [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures")]
        public static TMock Setup<TMock, TReturn>(this TMock mockObject,
                                                  Expression<Func<TMock, TReturn>> expression,
                                                  Func<TReturn> valueFunction) where TMock : class
        {
            return Setup(mockObject, expression, valueFunction, args => { });
        }

        /// <summary>
        /// Sets up a method of the specified mock object with return function and call back method.
        /// </summary>
        /// <typeparam name="TMock">The type of the mock.</typeparam>
        /// <typeparam name="TReturn">The type of the return.</typeparam>
        /// <param name="mockObject">The mock object.</param>
        /// <param name="expression">The expression to set up a method.</param>
        /// <param name="valueFunction">The return function.</param>
        /// <param name="callback">The callback.</param>
        /// <returns></returns>
        [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures")]
        public static TMock Setup<TMock, TReturn>(this TMock mockObject,
                                                  Expression<Func<TMock, TReturn>> expression,
                                                  Func<TReturn> valueFunction,
                                                  Action<object[]> callback) where TMock : class
        {
            if (expression == null)
            {
                throw new ArgumentNullException("expression");
            }
            if (valueFunction == null)
            {
                throw new ArgumentNullException("valueFunction");
            }
            if (callback == null)
            {
                throw new ArgumentNullException("callback");
            }
            MethodCallExpression methodCallExpression;
            if ((methodCallExpression = expression.Body as MethodCallExpression) == null)
            {
                throw new ArgumentException("Expression should be for Method(not Property).");
            }
            int count = methodCallExpression.Arguments.Count;
            ICallback iCallback = mockObject.Mock().Setup(expression).Returns(valueFunction);
            iCallback.SetupCallBack(count, callback);
            return mockObject;
        }

        /// <summary>
        /// Sets up a method of the specified mock object.
        /// </summary>
        /// <typeparam name="TMock">The type of the mock.</typeparam>
        /// <param name="mockObject">The mock object.</param>
        /// <param name="expression">The expression.</param>
        /// <returns></returns>
        [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures")]
        public static TMock Setup<TMock>(this TMock mockObject,
                                         Expression<Action<TMock>> expression) where TMock : class
        {
            return Setup(mockObject, expression, args => { });
        }

        /// <summary>
        /// Sets up a method of the specified mock object with call back method.
        /// </summary>
        /// <typeparam name="TMock">The type of the mock.</typeparam>
        /// <param name="mockObject">The mock object.</param>
        /// <param name="expression">The expression.</param>
        /// <param name="callback">The callback.</param>
        /// <returns></returns>
        [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures")]
        public static TMock Setup<TMock>(this TMock mockObject,
                                         Expression<Action<TMock>> expression,
                                         Action<object[]> callback) where TMock : class
        {
            if (expression == null)
            {
                throw new ArgumentNullException("expression");
            }
            if (callback == null)
            {
                throw new ArgumentNullException("callback");
            }
            MethodCallExpression methodCallExpression;
            if ((methodCallExpression = expression.Body as MethodCallExpression) == null)
            {
                throw new ArgumentException("Expression should be for Method(not Property).");
            }
            int count = methodCallExpression.Arguments.Count;
            ICallback iCallback = mockObject.Mock().Setup(expression);
            iCallback.SetupCallBack(count, callback);
            return mockObject;
        }

        /// <summary>
        /// Sets up a get property of the specified mock object.
        /// </summary>
        /// <typeparam name="TMock">The type of the mock.</typeparam>
        /// <typeparam name="TReturn">The type of the return.</typeparam>
        /// <param name="mockObject">The mock object.</param>
        /// <param name="expression">The expression.</param>
        /// <param name="value">The get value.</param>
        /// <returns></returns>
        [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures")]
        public static TMock SetupGet<TMock, TReturn>(this TMock mockObject,
                                                     Expression<Func<TMock, TReturn>> expression,
                                                     TReturn value) where TMock : class
        {
            return SetupGet(mockObject, expression, value, args => { });
        }

        /// <summary>
        /// Sets up a get property of the specified mock object with call back method.
        /// </summary>
        /// <typeparam name="TMock">The type of the mock.</typeparam>
        /// <typeparam name="TReturn">The type of the return.</typeparam>
        /// <param name="mockObject">The mock object.</param>
        /// <param name="expression">The expression.</param>
        /// <param name="value">The get value.</param>
        /// <param name="callback">The callback.</param>
        /// <returns></returns>
        [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures")]
        public static TMock SetupGet<TMock, TReturn>(this TMock mockObject,
                                                     Expression<Func<TMock, TReturn>> expression,
                                                     TReturn value,
                                                     Action<object[]> callback) where TMock : class
        {
            if (expression == null)
            {
                throw new ArgumentNullException("expression");
            }
            if (callback == null)
            {
                throw new ArgumentNullException("callback");
            }
            ICallback iCallback = mockObject.Mock().SetupGet(expression).Returns(value);
            iCallback.SetupCallBack(0, callback);
            return mockObject;
        }

        /// <summary>
        /// Sets up the get property of the specified mock object with get value fuction.
        /// </summary>
        /// <typeparam name="TMock">The type of the mock.</typeparam>
        /// <typeparam name="TReturn">The type of the return.</typeparam>
        /// <param name="mockObject">The mock object.</param>
        /// <param name="expression">The expression.</param>
        /// <param name="valueFunction">The get value function.</param>
        /// <returns></returns>
        [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures")]
        public static TMock SetupGet<TMock, TReturn>(this TMock mockObject,
                                                     Expression<Func<TMock, TReturn>> expression,
                                                     Func<TReturn> valueFunction) where TMock : class
        {
            return SetupGet(mockObject, expression, valueFunction, args => { });
        }

        /// <summary>
        /// Sets up a get property of the specified mock object with get value fuction and call back method.
        /// </summary>
        /// <typeparam name="TMock">The type of the mock.</typeparam>
        /// <typeparam name="TReturn">The type of the return.</typeparam>
        /// <param name="mockObject">The mock object.</param>
        /// <param name="expression">The expression.</param>
        /// <param name="valueFunction">The get value function.</param>
        /// <param name="callback">The callback.</param>
        /// <returns></returns>
        [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures")]
        public static TMock SetupGet<TMock, TReturn>(this TMock mockObject,
                                                     Expression<Func<TMock, TReturn>> expression,
                                                     Func<TReturn> valueFunction,
                                                     Action<object[]> callback) where TMock : class
        {
            if (expression == null)
            {
                throw new ArgumentNullException("expression");
            }
            if (valueFunction == null)
            {
                throw new ArgumentNullException("valueFunction");
            }
            if (callback == null)
            {
                throw new ArgumentNullException("callback");
            }
            ICallback iCallback = mockObject.Mock().SetupGet(expression).Returns(valueFunction);
            iCallback.SetupCallBack(0, callback);
            return mockObject;
        }

        /// <summary>
        /// Sets up a set property of the specified mock object.
        /// </summary>
        /// <typeparam name="TMock">The type of the mock.</typeparam>
        /// <param name="mockObject">The mock object.</param>
        /// <param name="expression">The expression.</param>
        /// <returns></returns>
        public static TMock SetupSet<TMock>(this TMock mockObject,
                                            Action<TMock> expression) where TMock : class
        {
            return SetupSet(mockObject, expression, args => { });
        }

        /// <summary>
        /// Sets up a set property of the specified mock object with call back method.
        /// </summary>
        /// <typeparam name="TMock">The type of the mock.</typeparam>
        /// <param name="mockObject">The mock object.</param>
        /// <param name="expression">The expression.</param>
        /// <param name="callback">The callback.</param>
        /// <returns></returns>
        public static TMock SetupSet<TMock>(this TMock mockObject,
                                            Action<TMock> expression,
                                            Action<object[]> callback) where TMock : class
        {
            if (expression == null)
            {
                throw new ArgumentNullException("expression");
            }
            if (callback == null)
            {
                throw new ArgumentNullException("callback");
            }
            ICallback iCallback = mockObject.Mock().SetupSet(expression);
            iCallback.SetupCallBack(0, callback);
            return mockObject;
        }

        /* Verify */

        /// <summary>
        /// Verifies a method of the specified mock object.
        /// </summary>
        /// <typeparam name="TMock">The type of the mock.</typeparam>
        /// <typeparam name="TReturn">The type of the return.</typeparam>
        /// <param name="mockObject">The mock object.</param>
        /// <param name="expression">The expression.</param>
        /// <returns></returns>
        [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures")]
        public static TMock Verify<TMock, TReturn>(this TMock mockObject, Expression<Func<TMock, TReturn>> expression)
            where TMock : class
        {
            if (expression == null)
            {
                throw new ArgumentNullException("expression");
            }
            if ((expression.Body as MethodCallExpression) == null)
            {
                throw new ArgumentException("Expression should be for Method(not Property).");
            }
            mockObject.Mock().Verify(expression);
            return mockObject;
        }

        /// <summary>
        /// Verifies a method of the specified mock object.
        /// </summary>
        /// <typeparam name="TMock">The type of the mock.</typeparam>
        /// <typeparam name="TReturn">The type of the return.</typeparam>
        /// <param name="mockObject">The mock object.</param>
        /// <param name="expression">The expression.</param>
        /// <param name="times">The times.</param>
        /// <returns></returns>
        [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures")]
        public static TMock Verify<TMock, TReturn>(this TMock mockObject, Expression<Func<TMock, TReturn>> expression, int times)
            where TMock : class
        {
            if (expression == null)
            {
                throw new ArgumentNullException("expression");
            }
            if ((expression.Body as MethodCallExpression) == null)
            {
                throw new ArgumentException("Expression should be for Method(not Property).");
            }
            mockObject.Mock().Verify(expression, Times.Exactly(times));
            return mockObject;
        }

        /// <summary>
        /// Verifies a method of the specified mock object.
        /// </summary>
        /// <typeparam name="TMock">The type of the mock.</typeparam>
        /// <param name="mockObject">The mock object.</param>
        /// <param name="expression">The expression.</param>
        /// <returns></returns>
        [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures")]
        public static TMock Verify<TMock>(this TMock mockObject, Expression<Action<TMock>> expression)
            where TMock : class
        {
            if (expression == null)
            {
                throw new ArgumentNullException("expression");
            }
            mockObject.Mock().Verify(expression);
            return mockObject;
        }

        /// <summary>
        /// Verifies a method of the specified mock object.
        /// </summary>
        /// <typeparam name="TMock">The type of the mock.</typeparam>
        /// <param name="mockObject">The mock object.</param>
        /// <param name="expression">The expression.</param>
        /// <param name="times">The times.</param>
        /// <returns></returns>
        [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures")]
        public static TMock Verify<TMock>(this TMock mockObject, Expression<Action<TMock>> expression, int times)
            where TMock : class
        {
            if (expression == null)
            {
                throw new ArgumentNullException("expression");
            }
            mockObject.Mock().Verify(expression, Times.Exactly(times));
            return mockObject;
        }

        /// <summary>
        /// Verifies a get property of the specified mock object.
        /// </summary>
        /// <typeparam name="TMock">The type of the mock.</typeparam>
        /// <typeparam name="TReturn">The type of the return.</typeparam>
        /// <param name="mockObject">The mock object.</param>
        /// <param name="expression">The expression.</param>
        /// <returns></returns>
        [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures")]
        public static TMock VerifyGet<TMock, TReturn>(this TMock mockObject, Expression<Func<TMock, TReturn>> expression)
            where TMock : class
        {
            if (expression == null)
            {
                throw new ArgumentNullException("expression");
            }
            if ((expression.Body as MemberExpression) == null)
            {
                throw new ArgumentException("Expression should be for Get Property.");
            }
            mockObject.Mock().VerifyGet(expression);
            return mockObject;
        }

        /// <summary>
        /// Verifies a get property of the specified mock object.
        /// </summary>
        /// <typeparam name="TMock">The type of the mock.</typeparam>
        /// <typeparam name="TReturn">The type of the return.</typeparam>
        /// <param name="mockObject">The mock object.</param>
        /// <param name="expression">The expression.</param>
        /// <param name="times">The times.</param>
        /// <returns></returns>
        [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures")]
        public static TMock VerifyGet<TMock, TReturn>(this TMock mockObject, Expression<Func<TMock, TReturn>> expression, int times)
            where TMock : class
        {
            if (expression == null)
            {
                throw new ArgumentNullException("expression");
            }
            if ((expression.Body as MemberExpression) == null)
            {
                throw new ArgumentException("Expression should be for Get Property.");
            }
            mockObject.Mock().VerifyGet(expression, Times.Exactly(times));
            return mockObject;
        }

        /// <summary>
        /// Verifies a set property of the specified mock object.
        /// </summary>
        /// <typeparam name="TMock">The type of the mock.</typeparam>
        /// <param name="mockObject">The mock object.</param>
        /// <param name="expression">The expression.</param>
        /// <returns></returns>
        public static TMock VerifySet<TMock>(this TMock mockObject, Action<TMock> expression)
            where TMock : class
        {
            if (expression == null)
            {
                throw new ArgumentNullException("expression");
            }
            mockObject.Mock().VerifySet(expression);
            return mockObject;
        }

        /// <summary>
        /// Verifies a set property of the specified mock object.
        /// </summary>
        /// <typeparam name="TMock">The type of the mock.</typeparam>
        /// <param name="mockObject">The mock object.</param>
        /// <param name="expression">The expression.</param>
        /// <param name="times">The times.</param>
        /// <returns></returns>
        public static TMock VerifySet<TMock>(this TMock mockObject, Action<TMock> expression, int times)
            where TMock : class
        {
            if (expression == null)
            {
                throw new ArgumentNullException("expression");
            }
            mockObject.Mock().VerifySet(expression, Times.Exactly(times));
            return mockObject;
        }

        /// <summary>
        /// Verifies all of the specified mock object.
        /// </summary>
        /// <typeparam name="TMock">The type of the mock.</typeparam>
        /// <param name="mockObject">The mock object.</param>
        /// <returns></returns>
        public static TMock VerifyAll<TMock>(this TMock mockObject) where TMock : class
        {
            mockObject.Mock().VerifyAll();
            return mockObject;
        }

        /* Event */

        /// <summary>
        /// Raises a event of the specified mock object.
        /// </summary>
        /// <typeparam name="TMock">The type of the mock.</typeparam>
        /// <param name="mockObject">The mock object.</param>
        /// <param name="eventExpression">The event expression.</param>
        /// <param name="args">The args for the event.</param>
        /// <returns></returns>
        public static TMock Raises<TMock>(this TMock mockObject, Action<TMock> eventExpression, params object[] args) where TMock : class
        {
            if (eventExpression == null)
            {
                throw new ArgumentNullException("eventExpression");
            }
            mockObject.Mock().Raise(eventExpression, args);
            return mockObject;
        }

        /// <summary>
        /// Raises a event of the specified mock object.
        /// </summary>
        /// <typeparam name="TMock">The type of the mock.</typeparam>
        /// <param name="mockObject">The mock object.</param>
        /// <param name="eventExpression">The event expression.</param>
        /// <param name="args">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        /// <returns></returns>
        public static TMock Raises<TMock>(this TMock mockObject, Action<TMock> eventExpression, EventArgs args) where TMock : class
        {
            if (eventExpression == null)
            {
                throw new ArgumentNullException("eventExpression");
            }
            mockObject.Mock().Raise(eventExpression, args);
            return mockObject;
        }

        /* Private Methods */

        [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
        private static void SetupCallBack(this ICallback iCallback, int count, Action<object[]> callBack)
        {
            switch (count)
            {
                case 0:
                    iCallback.Callback(() => callBack(new object[0]));
                    break;
                case 1:
                    iCallback.Callback(new Action<object>(
                                           arg1 => callBack(new[] {arg1})));
                    break;
                case 2:
                    iCallback.Callback(new Action<object, object>(
                                           (arg1, arg2) => callBack(new[] {arg1, arg2})));
                    break;
                case 3:
                    iCallback.Callback(new Action<object, object, object>(
                                           (arg1, arg2, arg3) => callBack(new[] {arg1, arg2, arg3})));
                    break;
                case 4:
                    iCallback.Callback(new Action<object, object, object, object>(
                                           (arg1, arg2, arg3, arg4) => callBack(new[] {arg1, arg2, arg3, arg4})));
                    break;
                case 5:
                    iCallback.Callback(new Action<object, object, object, object, object>(
                                           (arg1, arg2, arg3, arg4, arg5) => callBack(new[] {arg1, arg2, arg3, arg4, arg5})));
                    break;
                case 6:
                    iCallback.Callback(new Action<object, object, object, object, object, object>(
                                           (arg1, arg2, arg3, arg4, arg5, arg6) => callBack(new[] {arg1, arg2, arg3, arg4, arg5, arg6})));
                    break;
                case 7:
                    iCallback.Callback(new Action<object, object, object, object, object, object, object>(
                                           (arg1, arg2, arg3, arg4, arg5, arg6, arg7) => callBack(new[] {arg1, arg2, arg3, arg4, arg5, arg6, arg7})));
                    break;
                case 8:
                    iCallback.Callback(new Action<object, object, object, object, object, object, object, object>(
                                           (arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) => callBack(new[] {arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8})));
                    break;
                case 9:
                    iCallback.Callback(new Action<object, object, object, object, object, object, object, object, object>(
                                           (arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) => callBack(new[] {arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9})));
                    break;
                case 10:
                    iCallback.Callback(new Action<object, object, object, object, object, object, object, object, object, object>(
                                           (arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10) => callBack(new[] {arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10})));
                    break;
                default:
                    throw new NotSupportedException();
            }
        }
    }
}